<template>
  <div class="rtsp-video-player" :class="{ fullscreen: isFullscreen }">
    <!-- 视频容器 -->
    <div class="video-container">
      <video
        ref="videoRef"
        :controls="showControls"
        autoplay
        muted
        playsinline
        webkit-playsinline
        x5-playsinline
        x5-video-player-type="h5"
        x5-video-player-fullscreen="true"
        x5-video-ignore-metadata="true"
        x5-video-orientation="landscape"
        preload="auto"
        @loadedmetadata="onLoadedMetadata"
        @timeupdate="onTimeUpdate"
        @ended="onEnded"
        @play="isPlaying = true"
        @pause="isPlaying = false"
        @error="onVideoError"
        @canplay="onCanPlay"
        @loadstart="onLoadStart"
        @visibilitychange="onVisibilityChange"
        @stalled="onStalled"
        @suspend="onSuspend"
      >
        您的浏览器不支持视频播放
      </video>

      <!-- 加载中 -->
      <div class="loading-overlay" v-show="isLoading">
        <el-icon size="32" class="loading-icon">
          <Loading />
        </el-icon>
        <div class="loading-text">连接中...</div>
      </div>

      <!-- 错误提示 -->
      <div class="error-overlay" v-show="hasError">
        <el-icon size="32" class="error-icon">
          <Warning />
        </el-icon>
        <div class="error-text">{{ errorMessage }}</div>
        <el-button @click="retryConnection" type="primary" size="small">
          重试连接
        </el-button>
      </div>

      <!-- 状态信息 -->
      <!-- <div class="status-info" v-if="detectedFormat">
        <span class="format-tag">{{ detectedFormat }}</span>
        <span class="mode-tag">
          {{ 
            playbackMode === 'direct' ? '直接播放' : 
            playbackMode === 'flvjs' ? 'FLV播放' :
            playbackMode === 'hlsjs' ? 'HLS播放' :
            playbackMode === 'websocket' ? '转码播放' : '未知模式'
          }}
        </span>
      </div> -->
    </div>

    <!-- 控制面板 -->
    <div class="control-panel" v-if="!props.hideControls">
      <!-- 流地址输入 -->
      <div class="stream-input">
        <el-input
          :model-value="internalRtspUrl"
          @update:model-value="updateRtspUrl"
          placeholder="输入视频流URL (支持RTSP/RTMP/FLV/HLS/MP4)"
          size="small"
          clearable
        >
          <template #prepend>URL</template>
        </el-input>
        <el-button @click="startStream" type="primary" size="small">
          开始播放
        </el-button>
        <el-button @click="stopStream" type="danger" size="small">
          停止播放
        </el-button>
      </div>

      <!-- 状态显示 -->
      <div class="status-display">
        <el-tag :type="connectionStatus.type" size="small">
          {{ connectionStatus.text }}
        </el-tag>
        <span class="connection-time" v-if="connectionTime">
          连接时间: {{ connectionTime }}ms
        </span>
      </div>

      <!-- 预设流 -->
      <div class="preset-streams" v-if="showPresets">
        <el-button
          v-for="preset in streamPresets"
          :key="preset.url"
          @click="setStream(preset.url)"
          size="small"
          :type="internalRtspUrl === preset.url ? 'primary' : 'default'"
        >
          {{ preset.name }}
        </el-button>
      </div>
    </div>

    <!-- 全屏按钮 - 仅在非数据采集模式下显示 -->
    <el-button
      v-if="!props.hideControls"
      @click="toggleFullscreen"
      class="fullscreen-btn"
      :icon="isFullscreen ? ZoomOut : FullScreen"
      circle
      size="small"
    />
    
    <!-- 全屏模式下的缩小按钮 - 数据采集模式下也显示 -->
    <el-button
      v-if="isFullscreen"
      @click="toggleFullscreen"
      class="fullscreen-exit-btn"
      :icon="CircleClose"
      circle
      size="small"
    />
    

  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch } from "vue";
import {
  Loading,
  Warning,
  FullScreen,
  Aim,
  ZoomOut,
  Close,
  Remove,
  Minus,
  ArrowDown,
  ArrowLeft,
  Back,
  CloseBold,
  CircleClose
} from "@element-plus/icons-vue";
import flvjs from "flv.js";
import Hls from "hls.js";

const props = defineProps({
  // 视频流URL
  rtspUrl: {
    type: String,
    default: "",
  },
  // 是否隐藏控制面板
  hideControls: {
    type: Boolean,
    default: false,
  },
  // 是否显示预设流
  showPresets: {
    type: Boolean,
    default: true,
  },
  // 是否自动播放
  autoplay: {
    type: Boolean,
    default: true,
  },
  // 是否显示视频控件
  showControls: {
    type: Boolean,
    default: false,
  },
  // 视频状态 - 用于控制是否进行重连
  videoStatus: {
    type: String,
    default: "active", // active, disabled, offline
  },
  // 调试日志开关（启用后打印更详细信息）
  debugLogs: {
    type: Boolean,
    default: false,
  },
});

const emit = defineEmits(["play", "pause", "ended", "timeupdate", "error", "connected", "fullscreenChange", "reconnectFailed"]);

// 响应式数据
const videoRef = ref();
const isPlaying = ref(false);
const isLoading = ref(false);
const hasError = ref(false);
const errorMessage = ref("");
const isFullscreen = ref(false);
const connectionTime = ref(null);
const connectionStartTime = ref(null);
const keepAliveInterval = ref(null);
const reconnectFailCount = ref(0);
const maxReconnectAttempts = 3; // 最大重连尝试次数
const hasEmittedOffline = ref(false); // 是否已经发送了离线通知
const playbackCheckInterval = ref(null); // 播放检查定时器
const backgroundPlaybackInterval = ref(null); // 后台播放监控定时器

// 内部rtspUrl状态
const internalRtspUrl = ref(props.rtspUrl || "");

// 播放器实例
let flvPlayer = null;
let hlsPlayer = null;

// Windows 7 兼容性检测函数
const isWindows7 = () => {
  const userAgent = navigator.userAgent.toLowerCase();
  return userAgent.includes('windows nt 6.1') || userAgent.includes('windows 7');
};

// 电子（Chromium）能力检测：Win7 下 fMP4/H.264、TS 支持探测
const checkMseSupport = () => {
  const hasMSE = typeof window !== 'undefined' && !!window.MediaSource;
  const fmp4H264 = hasMSE && MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');
  const tsH264 = hasMSE && MediaSource.isTypeSupported('video/mp2t; codecs="avc1.42E01E,mp4a.40.2"');
  return { hasMSE, fmp4H264, tsH264 };
};

// 简易获取文本（带超时）
const fetchTextWithTimeout = async (url, timeoutMs = 3000) => {
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const res = await fetch(url, { signal: controller.signal });
    if (!res.ok) throw new Error('HTTP ' + res.status);
    return await res.text();
  } finally {
    clearTimeout(id);
  }
};

// 解析 m3u8，提取首个 variant 的 CODECS/RESOLUTION/BANDWIDTH
const probeM3U8Info = async (url) => {
  try {
    const text = await fetchTextWithTimeout(url, 4000);
    const lines = text.split(/\r?\n/);
    const variants = [];
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i].trim();
      if (line.startsWith('#EXT-X-STREAM-INF')) {
        const attrs = {};
        const attrText = line.substring(line.indexOf(':') + 1);
        attrText.split(',').forEach(kv => {
          const [k, v] = kv.split('=');
          if (k && v) attrs[k.trim()] = v.replace(/"/g, '').trim();
        });
        const uri = (i + 1 < lines.length) ? lines[i + 1].trim() : '';
        variants.push({ attrs, uri });
      }
    }
    if (variants.length > 0) {
      const v = variants[0];
      const res = v.attrs.RESOLUTION || '';
      const bw = v.attrs.BANDWIDTH || v.attrs['AVERAGE-BANDWIDTH'] || '';
      const codecs = v.attrs.CODECS || '';
      console.log('HLS(m3u8) 解析:', { url, CODECS: codecs, RESOLUTION: res, BANDWIDTH: bw, uri: v.uri });
      return { codecs, resolution: res, bandwidth: bw };
    }
  } catch (e) {
    console.warn('m3u8 解析失败:', e.message);
  }
  return null;
};

// 粗略判断 m3u8 分片类型（.ts / .mp4）
const detectHlsSegmentType = async (url) => {
  try {
    const text = await fetchTextWithTimeout(url, 3000);
    const lower = text.toLowerCase();
    if (lower.includes('.ts')) return 'ts';
    if (lower.includes('.mp4') || lower.includes('fmp4')) return 'mp4';
  } catch (e) {
    console.warn('m3u8 分片探测失败:', e);
  }
  return 'unknown';
};

// 连接状态
const connectionStatus = ref({
  type: "info",
  text: "未连接",
});

// 格式检测
const detectedFormat = ref("");
const playbackMode = ref("");

// 预设流列表
const streamPresets = ref([
  {
    name: "🌍 斯洛伐克湖景",
    url: "rtsp://stream.strba.sk:1935/strba/VYHLAD_JAZERO.stream"
  },
  {
    name: "🏢 办公楼监控",
    url: "rtsp://37.157.51.30/axis-media/media.amp"
  },
  {
    name: "🏭 工业监控",
    url: "rtsp://132.239.12.145:554/axis-media/media.amp"
  },
  {
    name: "🏠 住宅监控",
    url: "rtsp://196.21.92.82/axis-media/media.amp"
  },
  {
    name: "🏠 本地流测试",
    url: "rtsp://192.168.1.140:8554/mystream"
  },
  {
    name: "🏢 稳定测试流",
    url: "rtsp://demo:demo@ipvmdemo.dyndns.org:5541/onvif1"
  },
  {
    name: "📹 FLV测试流",
    url: "http://localhost:8080/test.flv"
  },
  {
    name: "📺 HLS测试流",
    url: "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8"
  },
  {
    name: "🎬 MP4测试流",
    url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
  }
]);

// 检测流格式
const detectStreamFormat = (url) => {
  const lowerUrl = url.toLowerCase();
  console.log('lowerUrl', lowerUrl);
  
  // 需要特殊播放器支持的格式
  if (lowerUrl.includes('.flv') || lowerUrl.includes('flv')) {
    return { format: 'FLV', mode: 'flvjs' };
  }
  if (lowerUrl.includes('.m3u8') || lowerUrl.includes('hls')) {
    return { format: 'HLS', mode: 'hlsjs' };
  }
  
  // 直接播放格式（浏览器原生支持）
  if (lowerUrl.includes('.mp4') || lowerUrl.includes('mp4')) {
    return { format: 'MP4', mode: 'direct' };
  }
  if (lowerUrl.includes('.webm') || lowerUrl.includes('webm')) {
    return { format: 'WebM', mode: 'direct' };
  }
  if (lowerUrl.includes('.ogg') || lowerUrl.includes('ogg')) {
    return { format: 'OGG', mode: 'direct' };
  }
  
  // 需要转码的格式
  if (lowerUrl.startsWith('rtsp://')) {
    return { format: 'RTSP', mode: 'websocket' };
  }
  if (lowerUrl.startsWith('rtmp://')) {
    return { format: 'RTMP', mode: 'websocket' };
  }
  
  // 默认当作需要转码
  return { format: 'Unknown', mode: 'websocket' };
};

// 检查WebSocket服务器是否可用
const checkWebSocketServer = async () => {
  return new Promise((resolve) => {
    // 直接尝试连接WebSocket服务器，不发送测试流
    const ws = new WebSocket('ws://localhost:9527/');
    const timeout = setTimeout(() => {
      ws.close();
      resolve(false);
    }, 3000);
    
    ws.onopen = () => {
      clearTimeout(timeout);
      ws.close();
      resolve(true);
    };
    
    ws.onerror = () => {
      clearTimeout(timeout);
      resolve(false);
    };
  });
};

// 直接播放流（不需要转码）
const playDirectStream = async (url) => {
  console.log('直接播放模式:', url);
  connectionStatus.value = { type: "warning", text: "连接中..." };
  isLoading.value = true;
  hasError.value = false;
  playbackMode.value = 'direct';
  
  // 设置连接超时
  const connectionTimeout = setTimeout(() => {
    if (isLoading.value) {
      console.warn('直接播放连接超时');
      showError("视频加载超时，请检查网络连接或稍后重试");
      connectionStatus.value = { type: "danger", text: "连接超时" };
      
      // 发射重连失败事件给父组件
      console.log('直接播放连接超时，发射reconnectFailed事件');
      emit("reconnectFailed", { 
        url: internalRtspUrl.value,
        attempts: 1,
        error: '直接播放连接超时'
      });
    }
  }, 15000); // 15秒超时
  
  const videoElement = videoRef.value;
  videoElement.src = url;
  
  // 检查是否为静态文件
  const isStaticFile = url.toLowerCase().includes('.mp4') || 
                      url.toLowerCase().includes('.webm') || 
                      url.toLowerCase().includes('.ogg');
  
  // 静态文件设置循环播放
  if (isStaticFile) {
    videoElement.loop = true;
    console.log('静态文件，启用循环播放');
  }
  
  // 视频事件监听
  videoElement.onloadstart = () => {
    console.log('视频开始加载');
  };
  
  videoElement.onloadedmetadata = () => {
    console.log('视频元数据加载完成');
    console.log('Direct 媒体信息:', { width: videoElement.videoWidth, height: videoElement.videoHeight, duration: videoElement.duration });
    clearTimeout(connectionTimeout);
    const time = Date.now() - connectionStartTime.value;
    connectionTime.value = time;
    connectionStatus.value = { type: "success", text: "已连接" };
    isLoading.value = false;
    reconnectFailCount.value = 0; // 连接成功时重置重连失败计数
    emit("connected", { time, url: internalRtspUrl.value });
  };
  
  videoElement.oncanplay = () => {
    console.log('视频可以播放');
    if (isLoading.value) {
      clearTimeout(connectionTimeout);
      const time = Date.now() - connectionStartTime.value;
      connectionTime.value = time;
      connectionStatus.value = { type: "success", text: "已连接" };
      isLoading.value = false;
      reconnectFailCount.value = 0; // 连接成功时重置重连失败计数
      emit("connected", { time, url: internalRtspUrl.value });
    }
  };
  
  videoElement.onerror = (e) => {
    console.error('视频播放错误:', e);
    clearTimeout(connectionTimeout);
    showError("视频格式不支持或网络连接异常");
    
    // 发射重连失败事件给父组件
    console.log('直接播放视频错误，发射reconnectFailed事件');
    emit("reconnectFailed", { 
      url: internalRtspUrl.value,
      attempts: 1,
      error: '视频格式不支持或网络连接异常'
    });
    
    emit("error", { type: "video", detail: "视频格式不支持或网络连接异常", url: internalRtspUrl.value });
  };
  
  // 自动播放
  if (props.autoplay) {
    try {
      await videoElement.play();
    } catch (error) {
      console.error('自动播放失败:', error);
    }
  }
};

// FLV播放（使用flv.js）
const playFlvStream = async (url) => {
  console.log('FLV播放模式:', url);
  connectionStatus.value = { type: "warning", text: "连接中..." };
  isLoading.value = true;
  hasError.value = false;
  playbackMode.value = 'flvjs';
  
  // 设置连接超时
  const connectionTimeout = setTimeout(() => {
    if (isLoading.value) {
      console.warn('FLV播放连接超时');
      showError("FLV视频加载超时，请检查网络连接或稍后重试");
      connectionStatus.value = { type: "danger", text: "连接超时" };
      
      emit("reconnectFailed", { 
        url: internalRtspUrl.value,
        attempts: 1,
        error: 'FLV播放连接超时'
      });
    }
  }, 15000); // 15秒超时

  try {
    // 检查 flv.js 是否可用
    if (typeof flvjs === 'undefined') {
      console.error('flv.js 未加载');
      showError("FLV播放器未加载，请刷新页面重试");
      return;
    }
    
    if (flvjs.isSupported()) {
      // Windows 7 兼容性配置
      const isWin7System = isWindows7();
      const flvConfig = {
        cors: true,
        enableStashBuffer: false,
        autoCleanupSourceBuffer: !isWin7System, // Windows 7 禁用自动清理
        fixAudioTimestampGap: false
      };
      
      if (isWin7System) {
        console.log('Windows 7 系统，使用兼容性配置');
        flvConfig.enableWorker = false; // Windows 7 禁用 Web Worker
      }
      
      // 创建flv.js播放器
      flvPlayer = flvjs.createPlayer({
        type: 'flv',
        url: url
      }, flvConfig);

      // 监听事件
      flvPlayer.on(flvjs.Events.LOADING_COMPLETE, () => {
        console.log('flv.js加载完成');
        clearTimeout(connectionTimeout);
        const time = Date.now() - connectionStartTime.value;
        connectionTime.value = time;
        connectionStatus.value = { type: "success", text: "已连接" };
        isLoading.value = false;
        reconnectFailCount.value = 0;
        emit("connected", { time, url: internalRtspUrl.value });
        
        startKeepAlive();
      });

      flvPlayer.on(flvjs.Events.LOADING, () => {
        console.log('flv.js开始加载数据');
      });

      flvPlayer.on(flvjs.Events.MEDIA_INFO, (mediaInfo) => {
        console.log('flv.js获取到媒体信息:', mediaInfo);
        try {
          console.log('FLV 媒体信息:', { videoCodec: mediaInfo.videoCodec, audioCodec: mediaInfo.audioCodec, width: mediaInfo.width, height: mediaInfo.height, fps: mediaInfo.fps });
        } catch {}
        if (isLoading.value) {
          clearTimeout(connectionTimeout);
          const time = Date.now() - connectionStartTime.value;
          connectionTime.value = time;
          connectionStatus.value = { type: "success", text: "已连接" };
          isLoading.value = false;
          reconnectFailCount.value = 0;
          emit("connected", { time, url: internalRtspUrl.value });
          
          startKeepAlive();
        }
      });

      flvPlayer.on(flvjs.Events.METADATA_ARRIVED, () => {
        console.log('flv.js元数据到达');
        if (isLoading.value) {
          clearTimeout(connectionTimeout);
          const time = Date.now() - connectionStartTime.value;
          connectionTime.value = time;
          connectionStatus.value = { type: "success", text: "已连接" };
          isLoading.value = false;
          reconnectFailCount.value = 0;
          emit("connected", { time, url: internalRtspUrl.value });
          
          startKeepAlive();
        }
      });

      flvPlayer.on(flvjs.Events.ERROR, (errType, errDetail) => {
        console.error('flv.js错误:', errType, errDetail);
        
        const isBackgroundError = document.hidden || 
          (errDetail && errDetail.message && 
           (errDetail.message.includes('SourceBuffer') || 
            errDetail.message.includes('InvalidStateError')));
        
        if (isBackgroundError) {
          console.log('检测到后台相关错误，静默处理');
          return;
        }
        
        clearTimeout(connectionTimeout);
        
        let friendlyError = "FLV视频流连接失败";
        if (errType === 'NetworkError') {
          friendlyError = "FLV网络连接异常，请检查网络设置";
        } else if (errType === 'MediaError') {
          friendlyError = "FLV视频格式不支持或流媒体服务器异常";
        } else if (errType === 'OtherError') {
          friendlyError = "FLV播放器内部错误，请刷新页面重试";
        }
        
        showError(friendlyError);
        connectionStatus.value = { type: "danger", text: "连接错误" };
        isLoading.value = false;
        
        emit("reconnectFailed", { 
          url: internalRtspUrl.value,
          attempts: 1,
          error: friendlyError
        });
        
        emit("error", { type: errType, detail: friendlyError, url: internalRtspUrl.value });
      });

      // 附加到视频元素并播放
      flvPlayer.attachMediaElement(videoRef.value);
      flvPlayer.load();
      
      if (props.autoplay) {
        flvPlayer.play();
      }
      
    } else {
      // Windows 7 兼容性：尝试原生播放
      const isWin7System = isWindows7();
      if (isWin7System) {
        console.log('Windows 7 系统，flv.js 不支持，尝试原生播放');
        showError("Windows 7 上 FLV 播放器不支持，尝试原生播放");
        // 尝试原生播放
        await playDirectStream(url);
      } else {
        showError("当前浏览器不支持FLV播放，请使用Chrome或Firefox浏览器");
        connectionStatus.value = { type: "danger", text: "浏览器不支持" };
      }
    }

  } catch (error) {
    console.error('启动FLV流失败:', error);
    showError("FLV视频流启动失败，请检查网络连接");
    connectionStatus.value = { type: "danger", text: "启动失败" };
  }
};

// HLS播放（使用hls.js）
const playHlsStream = async (url) => {
  console.log('HLS播放模式:', url);
  // 启动前尝试解析 m3u8 关键属性
  probeM3U8Info(url);
  connectionStatus.value = { type: "warning", text: "连接中..." };
  isLoading.value = true;
  hasError.value = false;
  playbackMode.value = 'hlsjs';
  
  // 设置连接超时
  const connectionTimeout = setTimeout(() => {
    if (isLoading.value) {
      console.warn('HLS播放连接超时');
      showError("HLS视频加载超时，请检查网络连接或稍后重试");
      connectionStatus.value = { type: "danger", text: "连接超时" };
      
      emit("reconnectFailed", { 
        url: internalRtspUrl.value,
        attempts: 1,
        error: 'HLS播放连接超时'
      });
    }
  }, 15000); // 15秒超时

  try {
    // 检查 Hls 是否可用
    if (typeof Hls === 'undefined') {
      console.error('Hls.js 未加载');
      showError("HLS播放器未加载，请刷新页面重试");
      return;
    }
    
    if (Hls.isSupported()) {
      // Windows 7 兼容性配置
      const isWin7System = isWindows7();
      const hlsConfig = {
        debug: props.debugLogs,
        enableWorker: !isWin7System, // Windows 7 禁用 Web Worker
        lowLatencyMode: !isWin7System, // Windows 7 禁用低延迟模式
        backBufferLength: isWin7System ? 30 : 90, // Windows 7 减少缓冲区
        // 增加缓冲管理参数以解决bufferStalledError
        maxBufferLength: 60, // 最大缓冲长度(秒)
        maxBufferSize: 60 * 1000 * 1024, // 最大缓冲大小(字节)
        startLevel: -1, // 自动选择合适的码率级别
        autoLevelEnabled: true, // 自动码率切换
        // 处理缓冲不足的情况
        maxBufferHole: 0.5, // 最大缓冲空洞(秒)
        highBufferWatchdogPeriod: 1, // 高缓冲监控周期(秒)
        nudgeMaxRetry: 3, // 缓冲不足时的最大重试次数
        // 增加初始缓冲时间
        startFragPrefetch: true, // 开始片段预取
        capLevelOnFPSDrop: true, // 根据FPS下降自动降低码率级别
        abrEwmaFast: 1.5, // 快速适应因子
        abrEwmaSlow: 1.0 // 慢速适应因子
      };
      
      if (isWin7System) {
        console.log('Windows 7 系统，使用 HLS 兼容性配置');
      }
      
      // 创建hls.js播放器
      hlsPlayer = new Hls(hlsConfig);
      console.log('HLS Player created with config:', hlsConfig);

      // 监听事件
      hlsPlayer.on(Hls.Events.MANIFEST_PARSED, () => {
        console.log('HLS MANIFEST_PARSED 事件触发');
        try {
          const levels = hlsPlayer.levels || [];
          const info = levels.map((l, idx) => ({ idx, width: l.width, height: l.height, bitrate: l.bitrate, codecs: l.codecSet || l.codec || '' }));
          console.log('HLS 清单 levels:', info);
        } catch {}
        console.log('HLS清单解析完成');
        clearTimeout(connectionTimeout);
        const time = Date.now() - connectionStartTime.value;
        connectionTime.value = time;
        connectionStatus.value = { type: "success", text: "已连接" };
        isLoading.value = false;
        reconnectFailCount.value = 0;
        emit("connected", { time, url: internalRtspUrl.value });
        
        startKeepAlive();
      });

      hlsPlayer.on(Hls.Events.MEDIA_ATTACHED, () => {
        console.log('HLS媒体已附加');
      });

      hlsPlayer.on(Hls.Events.LEVEL_LOADED, (_, data) => {
        try {
          console.log('HLS 级别已加载:', { id: data?.level, details: { totalduration: data?.details?.totalduration, targetduration: data?.details?.targetduration } });
        } catch {}
        if (isLoading.value) {
          clearTimeout(connectionTimeout);
          const time = Date.now() - connectionStartTime.value;
          connectionTime.value = time;
          connectionStatus.value = { type: "success", text: "已连接" };
          isLoading.value = false;
          reconnectFailCount.value = 0;
          emit("connected", { time, url: internalRtspUrl.value });
          
          startKeepAlive();
        }
      });

      hlsPlayer.on(Hls.Events.ERROR, (event, data) => {
        console.error('HLS错误:', event, data);
        
        // 专门处理bufferStalledError
        if (data.details && data.details === 'bufferStalledError') {
          console.log('bufferStalledError已在专用处理器中处理');
          return;
        }
        
        const isBackgroundError = document.hidden || 
          (data && data.details && 
           (data.details.includes('SourceBuffer') || 
            data.details.includes('InvalidStateError')));
        
        if (isBackgroundError) {
          console.log('检测到后台相关错误，静默处理');
          return;
        }
        
        clearTimeout(connectionTimeout);
        
        let friendlyError = "HLS视频流连接失败";
        if (data.type === 'NETWORK_ERROR') {
          friendlyError = "HLS网络连接异常，请检查网络设置";
        } else if (data.type === 'MEDIA_ERROR') {
          friendlyError = "HLS视频格式不支持或流媒体服务器异常";
        } else if (data.type === 'OTHER_ERROR') {
          friendlyError = "HLS播放器内部错误，请刷新页面重试";
        }
        
        showError(friendlyError);
        connectionStatus.value = { type: "danger", text: "连接错误" };
        isLoading.value = false;
        
        emit("reconnectFailed", { 
          url: internalRtspUrl.value,
          attempts: 1,
          error: friendlyError
        });
        
        emit("error", { type: data.type, detail: friendlyError, url: internalRtspUrl.value });
      });
      
      // 监听BUFFER_STALLED_ERROR事件
      hlsPlayer.on(Hls.Events.BUFFER_STALLED_ERROR, (event, data) => {
        console.warn('HLS缓冲停滞错误:', event, data);
        
        // 尝试恢复播放 - 不显示错误，静默处理
        if (videoRef.value && !document.hidden) {
          console.log('尝试恢复HLS缓冲停滞...');
          
          // 方法1: 尝试暂停后恢复播放
          try {
            videoRef.value.pause();
            setTimeout(() => {
              videoRef.value.play().catch(e => {
                console.warn('恢复播放失败:', e);
              });
            }, 500);
          } catch (e) {
            console.warn('暂停/播放操作失败:', e);
          }
          
          // 方法2: 尝试调整当前播放位置到已缓冲区域
          setTimeout(() => {
            try {
              const buffered = videoRef.value.buffered;
              if (buffered.length > 0) {
                const currentTime = videoRef.value.currentTime;
                const bufferedEnd = buffered.end(buffered.length - 1);
                
                // 如果当前时间接近或超过已缓冲区域的末尾，回退一点
                if (currentTime >= bufferedEnd - 0.5) {
                  const newTime = Math.max(0, bufferedEnd - 1);
                  console.log(`调整播放位置: 从${currentTime.toFixed(2)}到${newTime.toFixed(2)}`);
                  videoRef.value.currentTime = newTime;
                }
              }
            } catch (e) {
              console.warn('调整播放位置失败:', e);
            }
          }, 1000);
          
          // 方法3: 对于HLS流，尝试降低码率
          if (playbackMode.value === 'hlsjs' && hlsPlayer) {
            try {
              const currentLevel = hlsPlayer.currentLevel;
              const levels = hlsPlayer.levels || [];
              
              // 只在有多个码率级别且当前不是最低级别时降低
              if (levels.length > 1 && currentLevel > 0) {
                console.log(`尝试降低HLS码率级别: 从${currentLevel}降到${currentLevel - 1}`);
                hlsPlayer.currentLevel = currentLevel - 1;
              }
            } catch (e) {
              console.warn('调整HLS码率级别失败:', e);
            }
          }
        }
      });

      // 加载HLS流
      hlsPlayer.loadSource(url);
      hlsPlayer.attachMedia(videoRef.value);
      
      if (props.autoplay) {
        hlsPlayer.startLoad();
      }
      
    } else if (videoRef.value.canPlayType('application/vnd.apple.mpegurl')) {
      // 原生HLS支持（Safari）
      console.log('使用原生HLS支持');
      const videoElement = videoRef.value;
      videoElement.src = url;
      
      videoElement.onloadedmetadata = () => {
        clearTimeout(connectionTimeout);
        const time = Date.now() - connectionStartTime.value;
        connectionTime.value = time;
        connectionStatus.value = { type: "success", text: "已连接" };
        isLoading.value = false;
        reconnectFailCount.value = 0;
        emit("connected", { time, url: internalRtspUrl.value });
        
        startKeepAlive();
      };
      
      videoElement.onerror = (e) => {
        clearTimeout(connectionTimeout);
        showError("HLS视频格式不支持或网络连接异常");
        emit("reconnectFailed", { 
          url: internalRtspUrl.value,
          attempts: 1,
          error: 'HLS视频格式不支持或网络连接异常'
        });
        emit("error", { type: "video", detail: "HLS视频格式不支持或网络连接异常", url: internalRtspUrl.value });
      };
      
      if (props.autoplay) {
        try {
          await videoElement.play();
        } catch (error) {
          console.error('HLS自动播放失败:', error);
        }
      }
    } else {
      // Windows 7 兼容性：尝试原生播放
      const isWin7System = isWindows7();
      if (isWin7System) {
        console.log('Windows 7 系统，HLS 不支持，尝试原生播放');
        showError("Windows 7 上 HLS 播放器不支持，尝试原生播放");
        // 尝试原生播放
        await playDirectStream(url);
      } else {
        showError("当前浏览器不支持HLS播放，请使用Chrome、Firefox或Safari浏览器");
        connectionStatus.value = { type: "danger", text: "浏览器不支持" };
      }
    }

  } catch (error) {
    console.error('启动HLS流失败:', error);
    showError("HLS视频流启动失败，请检查网络连接");
    connectionStatus.value = { type: "danger", text: "启动失败" };
  }
};

// WebSocket转码播放
const playWebSocketStream = async (url) => {
  console.log('WebSocket转码模式:', url);
  connectionStatus.value = { type: "warning", text: "检查服务器..." };
  playbackMode.value = 'websocket';
  
  // 检查WebSocket服务器
  const serverAvailable = await checkWebSocketServer();
  if (!serverAvailable) {
    showError("视频转码服务未启动，请联系管理员");
    return;
  }
  
  connectionStatus.value = { type: "warning", text: "连接中..." };
  isLoading.value = true;
  hasError.value = false;
  
  // 设置连接超时
  const connectionTimeout = setTimeout(() => {
    if (isLoading.value) {
      console.warn('WebSocket播放连接超时');
      showError("视频流连接超时，请检查网络或稍后重试");
      connectionStatus.value = { type: "danger", text: "连接超时" };
      
      // 发射重连失败事件给父组件
      console.log('WebSocket连接超时，发射reconnectFailed事件');
      emit("reconnectFailed", { 
        url: internalRtspUrl.value,
        attempts: 1,
        error: 'WebSocket播放连接超时'
      });
    }
  }, 15000); // 15秒超时

  try {
    if (flvjs.isSupported()) {
      // 创建flv.js播放器
      const wsUrl = `ws://localhost:9527/${url}`;
      
      // Windows 7 兼容性配置
      const isWin7System = isWindows7();
      const flvConfig = {
        cors: true,
        enableStashBuffer: false,
        autoCleanupSourceBuffer: !isWin7System, // Windows 7 禁用自动清理
        fixAudioTimestampGap: false
      };
      
      if (isWin7System) {
        console.log('Windows 7 系统，转码播放使用兼容性配置');
        flvConfig.enableWorker = false; // Windows 7 禁用 Web Worker
      }
      
      flvPlayer = flvjs.createPlayer({
        type: 'flv',
        url: wsUrl
      }, flvConfig);

      // 监听事件
      flvPlayer.on(flvjs.Events.LOADING_COMPLETE, () => {
        console.log('flv.js加载完成');
        clearTimeout(connectionTimeout);
        const time = Date.now() - connectionStartTime.value;
        connectionTime.value = time;
        connectionStatus.value = { type: "success", text: "已连接" };
        isLoading.value = false;
        reconnectFailCount.value = 0; // 连接成功时重置重连失败计数
        emit("connected", { time, url: internalRtspUrl.value });
        
        // 启动保持播放机制
        startKeepAlive();
      });

      flvPlayer.on(flvjs.Events.LOADING, () => {
        console.log('flv.js开始加载数据');
      });

      flvPlayer.on(flvjs.Events.MEDIA_INFO, (mediaInfo) => {
        console.log('flv.js获取到媒体信息:', mediaInfo);
        // 获取到媒体信息时也认为连接成功
        if (isLoading.value) {
          clearTimeout(connectionTimeout);
          const time = Date.now() - connectionStartTime.value;
          connectionTime.value = time;
          connectionStatus.value = { type: "success", text: "已连接" };
          isLoading.value = false;
          reconnectFailCount.value = 0; // 连接成功时重置重连失败计数
          emit("connected", { time, url: internalRtspUrl.value });
          
          // 启动保持播放机制
          startKeepAlive();
        }
      });

      flvPlayer.on(flvjs.Events.STATISTICS_INFO, (stats) => {
        // console.log('flv.js统计信息:', stats);
      });

      flvPlayer.on(flvjs.Events.SCRIPTDATA_ARRIVED, () => {
        console.log('flv.js脚本数据到达');
      });

      flvPlayer.on(flvjs.Events.METADATA_ARRIVED, () => {
        console.log('flv.js元数据到达');
        // 元数据到达时也认为连接成功
        if (isLoading.value) {
          clearTimeout(connectionTimeout);
          const time = Date.now() - connectionStartTime.value;
          connectionTime.value = time;
          connectionStatus.value = { type: "success", text: "已连接" };
          isLoading.value = false;
          reconnectFailCount.value = 0; // 连接成功时重置重连失败计数
          emit("connected", { time, url: internalRtspUrl.value });
          
          // 启动保持播放机制
          startKeepAlive();
        }
      });

      flvPlayer.on(flvjs.Events.ERROR, (errType, errDetail) => {
        console.error('flv.js错误:', errType, errDetail);
        
        // 检查是否是后台相关的错误
        const isBackgroundError = document.hidden || 
          (errDetail && errDetail.message && 
           (errDetail.message.includes('SourceBuffer') || 
            errDetail.message.includes('InvalidStateError')));
        
        if (isBackgroundError) {
          console.log('检测到后台相关错误，静默处理');
          // 后台错误时不显示错误信息，不触发重连
          return;
        }
        
        clearTimeout(connectionTimeout);
        
        // 根据错误类型提供友好的错误信息
        let friendlyError = "视频流连接失败";
        if (errType === 'NetworkError') {
          console.log('网络连接异常，请检查网络设置');
          friendlyError = "网络连接异常，请检查网络设置";
        } else if (errType === 'MediaError') {
          console.log('视频格式不支持或流媒体服务器异常');
          friendlyError = "视频格式不支持或流媒体服务器异常";
        } else if (errType === 'OtherError') {
          console.log('播放器内部错误，请刷新页面重试');
          friendlyError = "播放器内部错误，请刷新页面重试";
        }
        
        showError(friendlyError);
        connectionStatus.value = { type: "danger", text: "连接错误" };
        isLoading.value = false;
        
        // 发射重连失败事件给父组件
        console.log('flv.js错误，发射reconnectFailed事件');
        emit("reconnectFailed", { 
          url: internalRtspUrl.value,
          attempts: 1,
          error: friendlyError
        });
        
        emit("error", { type: errType, detail: friendlyError, url: internalRtspUrl.value });
      });

      // 附加到视频元素并播放
      flvPlayer.attachMediaElement(videoRef.value);
      flvPlayer.load();
      
      if (props.autoplay) {
        flvPlayer.play();
      }
      
    } else {
      showError("当前浏览器不支持视频播放，请使用Chrome或Firefox浏览器");
      connectionStatus.value = { type: "danger", text: "浏览器不支持" };
    }

  } catch (error) {
    console.error('启动流失败:', error);
    showError("视频流启动失败，请检查网络连接");
    connectionStatus.value = { type: "danger", text: "启动失败" };
  }
};

// 更新RTSP URL
const updateRtspUrl = (url) => {
  internalRtspUrl.value = url;
};

// 设置流地址
const setStream = (url) => {
  internalRtspUrl.value = url;
};

// 开始播放流
const startStream = async () => {
  if (!internalRtspUrl.value) {
    showError("请输入有效的视频流地址");
    return;
  }

  // 检查视频状态，如果停用则不启动播放
  if (!shouldAttemptReconnect()) {
    console.log('视频状态为停用，不启动播放');
    connectionStatus.value = { type: "info", text: "已停用" };
    return;
  }

  stopStream();
  connectionStartTime.value = Date.now();
  reconnectFailCount.value = 0;
  
  const formatInfo = detectStreamFormat(internalRtspUrl.value);
  detectedFormat.value = formatInfo.format;
  
  console.log(`检测到格式: ${formatInfo.format}, 播放模式: ${formatInfo.mode}`);
  
  if (formatInfo.mode === 'direct') {
    await playDirectStream(internalRtspUrl.value);
  } else if (formatInfo.mode === 'flvjs') {
    await playFlvStream(internalRtspUrl.value);
  } else if (formatInfo.mode === 'hlsjs') {
    // 不区分环境，始终打印能力与分片类型
    const supportInfo = checkMseSupport();
    console.log('MSE 能力探测:', supportInfo);
    let segType = 'unknown';
    try { segType = await detectHlsSegmentType(internalRtspUrl.value); } catch {}
    console.log('m3u8 分片类型推断:', segType);

    // Win7 兼容性：若为 Win7，且 m3u8 为 fMP4 分片或 fMP4 MSE 不支持，则回退至 WebSocket→FLV
    const isWin7System = isWindows7();
    if (isWin7System) {
      const { fmp4H264, tsH264 } = supportInfo;
      const likelyFmp4 = segType === 'mp4' || (!tsH264 && !fmp4H264);
      if (likelyFmp4 && !fmp4H264) {
        console.warn('检测到 Win7 对 fMP4/H.264 支持不足，回退到 WebSocket→FLV 播放');
        await playWebSocketStream(internalRtspUrl.value);
        return;
      }
    }
    await playHlsStream(internalRtspUrl.value);
  } else {
    await playWebSocketStream(internalRtspUrl.value);
  }
};

// 停止播放流
const stopStream = () => {
  // 停止保持播放机制
  stopKeepAlive();
  
  // 清理flv.js播放器
  if (flvPlayer) {
    flvPlayer.pause();
    flvPlayer.unload();
    flvPlayer.detachMediaElement();
    flvPlayer.destroy();
    flvPlayer = null;
  }
  
  // 清理hls.js播放器
  if (hlsPlayer) {
    hlsPlayer.destroy();
    hlsPlayer = null;
  }
  
  const videoElement = videoRef.value;
  if (videoElement) {
    videoElement.src = '';
    videoElement.load();
  }
  
  connectionStatus.value = { type: "info", text: "已停止" };
  isLoading.value = false;
  hasError.value = false;
  connectionTime.value = null;
  detectedFormat.value = "";
  playbackMode.value = "";
  reconnectFailCount.value = 0;
};

// 重试连接
const retryConnection = () => {
  startStream();
};

// 显示错误
const showError = (message) => {
  errorMessage.value = message;
  hasError.value = true;
  isLoading.value = false;
};

// 自定义全屏切换 - 不使用浏览器原生全屏
const toggleFullscreen = () => {
  isFullscreen.value = !isFullscreen.value;
  
  if (isFullscreen.value) {
    // 进入全屏模式
    document.body.style.overflow = 'hidden'; // 防止页面滚动
  } else {
    // 退出全屏模式
    document.body.style.overflow = '';
  }
  
  // 发射全屏状态改变事件
  emit("fullscreenChange", isFullscreen.value);
};

// 视频事件处理
const onLoadedMetadata = () => {
  // 直接播放模式下，元数据加载完成表示连接成功
  if (playbackMode.value === 'direct') {
    const time = Date.now() - connectionStartTime.value;
    connectionTime.value = time;
    connectionStatus.value = { type: "success", text: "已连接" };
    isLoading.value = false;
    reconnectFailCount.value = 0; // 连接成功时重置重连失败计数
    emit("connected", { time, url: internalRtspUrl.value });
  }
};

const onCanPlay = () => {
  // 直接播放模式下，可以播放时表示连接成功
  if (playbackMode.value === 'direct' && isLoading.value) {
    const time = Date.now() - connectionStartTime.value;
    connectionTime.value = time;
    connectionStatus.value = { type: "success", text: "已连接" };
    isLoading.value = false;
    reconnectFailCount.value = 0; // 连接成功时重置重连失败计数
    emit("connected", { time, url: internalRtspUrl.value });
  }
  
  // 启动保持播放机制
  startKeepAlive();
};

const onLoadStart = () => {
  // 开始加载时清除错误状态
  hasError.value = false;
  errorMessage.value = "";
};

const onTimeUpdate = () => {
  emit("timeupdate", videoRef.value?.currentTime || 0);
};

const onEnded = () => {
  isPlaying.value = false;
  emit("ended");
};

const onVideoError = (event) => {
  console.warn("视频播放错误:", event);
  
  // 后台时的错误处理更宽松
  if (document.hidden) {
    console.log("后台视频错误，尝试恢复播放");
    // 后台错误时不显示错误信息，只尝试恢复播放
    setTimeout(() => {
      if (document.hidden && videoRef.value && videoRef.value.paused) {
        videoRef.value.play().catch(() => {
          // 静默处理后台播放错误
        });
      }
    }, 1000);
    return;
  }
  
  showError("视频播放错误");
  emit("error", { type: "video", detail: event });
  
  // 如果是正常播放时出现错误，也触发重连机制
  if (reconnectFailCount.value === 0 && shouldAttemptReconnect()) {
    console.log("正常播放时出现错误，启动重连机制");
    reconnectFailCount.value = 1;
    forceVideoReconnect(videoRef.value);
  }
};

// 监听视频网络状态变化
const onStalled = () => {
  console.warn("视频加载停滞");
  
  // 如果页面在后台，不处理错误
  if (document.hidden) {
    console.log("页面在后台，忽略视频停滞");
    return;
  }
  
  if (reconnectFailCount.value === 0 && shouldAttemptReconnect()) {
    console.log("视频加载停滞，启动重连机制");
    reconnectFailCount.value = 1;
    forceVideoReconnect(videoRef.value);
  }
};

const onSuspend = () => {
  console.warn("视频加载暂停");
  
  // 如果页面在后台，不处理错误
  if (document.hidden) {
    console.log("页面在后台，忽略视频暂停");
    return;
  }
  
  if (reconnectFailCount.value === 0 && shouldAttemptReconnect()) {
    console.log("视频加载暂停，启动重连机制");
    reconnectFailCount.value = 1;
    forceVideoReconnect(videoRef.value);
  }
};

// 处理页面可见性变化
const onVisibilityChange = () => {
  const videoElement = videoRef.value;
  if (!videoElement) return;
  
  if (document.hidden) {
    // 页面隐藏时，暂停检测机制，保持视频播放
    console.log('页面隐藏，暂停检测机制，保持视频播放');
    
    // 暂停保活检测，避免后台误判
    if (keepAliveInterval.value) {
      clearInterval(keepAliveInterval.value);
      keepAliveInterval.value = null;
    }
    if (playbackCheckInterval.value) {
      clearInterval(playbackCheckInterval.value);
      playbackCheckInterval.value = null;
    }
    
    // 后台播放处理 - 使用更积极的方式
    const ensureBackgroundPlayback = () => {
      // 确保视频继续播放
      if (videoElement.paused && props.autoplay) {
        videoElement.play().catch(error => {
          console.warn('后台播放失败，尝试其他方法:', error);
          // 如果直接播放失败，尝试其他方法
          setTimeout(() => {
            if (document.hidden && videoElement.paused) {
              // 尝试重新加载视频源
              const currentSrc = videoElement.src;
              videoElement.src = currentSrc;
              videoElement.load();
              videoElement.play().catch(() => {
                console.warn('后台播放最终失败');
              });
            }
          }, 1000);
        });
      }
      
      // 对于 flv.js 播放器，确保继续播放
      if (flvPlayer && (playbackMode.value === 'websocket' || playbackMode.value === 'flvjs')) {
        try {
          if (flvPlayer.paused && props.autoplay) {
            flvPlayer.play().catch(error => {
              console.warn('flv.js 后台播放失败:', error);
            });
          }
        } catch (error) {
          console.warn('flv.js 后台播放处理失败:', error);
        }
      }
      
      // 对于 hls.js 播放器，确保继续播放
      if (hlsPlayer && playbackMode.value === 'hlsjs') {
        try {
          if (videoElement.paused && props.autoplay) {
            videoElement.play().catch(error => {
              console.warn('hls.js 后台播放失败:', error);
            });
          }
        } catch (error) {
          console.warn('hls.js 后台播放处理失败:', error);
        }
      }
    };
    
    // 立即尝试播放
    ensureBackgroundPlayback();
    
    // 延迟再次尝试，确保播放
    setTimeout(ensureBackgroundPlayback, 500);
    setTimeout(ensureBackgroundPlayback, 1000);
    setTimeout(ensureBackgroundPlayback, 2000);
    
    // 启动后台播放监控
    if (!backgroundPlaybackInterval.value) {
      backgroundPlaybackInterval.value = setInterval(() => {
        if (document.hidden) {
          // 检查视频是否在播放
          if (videoElement.paused && props.autoplay) {
            console.log('后台监控：检测到视频暂停，尝试恢复播放');
            videoElement.play().catch(error => {
              console.warn('后台监控：恢复播放失败:', error);
            });
          }
          
          // 检查 flv.js 播放器
          if (flvPlayer && (playbackMode.value === 'websocket' || playbackMode.value === 'flvjs') && flvPlayer.paused && props.autoplay) {
            try {
              flvPlayer.play().catch(error => {
                console.warn('后台监控：flv.js 恢复播放失败:', error);
              });
            } catch (error) {
              console.warn('后台监控：flv.js 播放处理失败:', error);
            }
          }
          
          // 检查 hls.js 播放器
          if (hlsPlayer && playbackMode.value === 'hlsjs' && videoElement.paused && props.autoplay) {
            try {
              videoElement.play().catch(error => {
                console.warn('后台监控：hls.js 恢复播放失败:', error);
              });
            } catch (error) {
              console.warn('后台监控：hls.js 播放处理失败:', error);
            }
          }
        }
      }, 3000); // 每3秒检查一次
    }
  } else {
    // 页面显示时，重新启动检测机制
    console.log('页面显示，重新启动检测机制');
    
    // 确保视频正在播放
    if (videoElement.paused && props.autoplay) {
      videoElement.play().catch(error => {
        console.warn('恢复播放失败:', error);
      });
    }
    
    // 对于 flv.js 播放器
    if (flvPlayer && (playbackMode.value === 'websocket' || playbackMode.value === 'flvjs')) {
      try {
        if (flvPlayer.paused && props.autoplay) {
          flvPlayer.play().catch(error => {
            console.warn('flv.js 恢复播放失败:', error);
          });
        }
      } catch (error) {
        console.warn('flv.js 恢复播放处理失败:', error);
      }
    }
    
    // 对于 hls.js 播放器
    if (hlsPlayer && playbackMode.value === 'hlsjs') {
      try {
        if (videoElement.paused && props.autoplay) {
          videoElement.play().catch(error => {
            console.warn('hls.js 恢复播放失败:', error);
          });
        }
      } catch (error) {
        console.warn('hls.js 恢复播放处理失败:', error);
      }
    }
    
    // 停止后台播放监控
    if (backgroundPlaybackInterval.value) {
      clearInterval(backgroundPlaybackInterval.value);
      backgroundPlaybackInterval.value = null;
    }
    
    // 重新启动保活检测
    if (!keepAliveInterval.value) {
      startKeepAlive();
    }
  }
};

// 保持视频播放的机制
const startKeepAlive = () => {
  if (keepAliveInterval.value) {
    clearInterval(keepAliveInterval.value);
  }

  // 重置状态
  reconnectFailCount.value = 0;
  hasEmittedOffline.value = false; // 重置离线标志
  
  // 对于直接播放的静态文件，使用更温和的检测
  const isStaticFile = () => {
    if (playbackMode.value !== 'direct') return false;
    const url = internalRtspUrl.value.toLowerCase();
    return url.includes('.mp4') || url.includes('.webm') || url.includes('.ogg');
  };
  
  const isStatic = isStaticFile();
  const checkInterval = isStatic ? 10000 : 2000; // 静态文件10秒检查一次，实时流2秒检查一次
  
  keepAliveInterval.value = setInterval(() => {
    const videoElement = videoRef.value;
    
    if (!videoElement || !props.autoplay) return;
    
    // 如果页面在后台，跳过检测
    if (document.hidden) {
      return;
    }
    
    // 视频正在播放：重置状态
    if (!videoElement.paused) {
      // 对于静态文件，不进行实时流检测
      if (!isStatic) {
        checkIfPlayingLive(videoElement);
      }
      return;
    }
    
    // 检查是否应该进行重连
    if (!shouldAttemptReconnect()) {
      return;
    }
    
    // 对于静态文件，只在播放结束时重新开始，不进行重连
    if (isStatic) {
      console.log('静态文件播放结束，重新开始播放');
      videoElement.currentTime = 0;
      videoElement.play().catch(error => {
        console.warn('静态文件重新播放失败:', error);
      });
      return;
    }
    
    // 视频暂停且未超过最大重试次数（仅对实时流）
    if (reconnectFailCount.value < 3) {
      console.log(`检测到视频暂停，第${reconnectFailCount.value + 1}次尝试重连`);
      
      // 强制重新加载视频源，避免播放缓存
      forceVideoReconnect(videoElement);
    } 
    // 三次重连失败：发送离线通知
    else {
      console.error(`视频重连失败3次，通知父组件设置离线状态`);
      stopKeepAlive();
      emitReconnectFailed();
    }
  }, checkInterval);
};

// 强制视频重新连接（不播放缓存）
const forceVideoReconnect = (videoElement) => {
  // 对于静态文件，不进行强制重连
  if (playbackMode.value === 'direct') {
    const url = internalRtspUrl.value.toLowerCase();
    if (url.includes('.mp4') || url.includes('.webm') || url.includes('.ogg')) {
      console.log('静态文件格式，跳过强制重连');
      return;
    }
  }
  
  // 保存当前时间戳作为重连标识
  const reconnectTimestamp = Date.now();
  
  // 临时关闭视频元素的自动播放
  const wasAutoplay = videoElement.autoplay;
  videoElement.autoplay = false;
  
  // 保存当前播放位置
  const wasPlaying = !videoElement.paused;
  const currentTime = videoElement.currentTime;
  
  // 强制重新加载视频源（避免播放缓存）
  const originalSrc = videoElement.src;
  videoElement.src = "";
  videoElement.load();
  
  // 重新设置原始视频源（添加随机参数避免缓存）
  videoElement.src = `${originalSrc}?reconnect=${reconnectTimestamp}`;
  videoElement.load();
  
  // 恢复播放设置
  videoElement.autoplay = wasAutoplay;
  videoElement.currentTime = currentTime;
  
  // 增加重连计数器
  reconnectFailCount.value++;
  
  // 尝试播放
  videoElement.play()
    .then(() => {
      // 恢复播放位置
      if (wasPlaying) {
        videoElement.currentTime = currentTime;
      }
      
      // 启动深度检测
      checkPlaybackStatus(videoElement, reconnectTimestamp);
    })
    .catch(error => handlePlayError(error));
};

// 检查是否应该进行重连
const shouldAttemptReconnect = () => {
  // 如果视频状态是停用的，不进行重连
  if (props.videoStatus === 'disabled' || props.videoStatus === 'offline') {
    console.log('视频状态为停用，跳过重连');
    return false;
  }
  return true;
};

// 检查视频是否在播放实时流
  const checkIfPlayingLive = (videoElement) => {
    // 对于静态文件，不进行实时流检测
    if (playbackMode.value === 'direct') {
      const url = internalRtspUrl.value.toLowerCase();
      if (url.includes('.mp4') || url.includes('.webm') || url.includes('.ogg')) {
        console.log('静态文件格式，跳过实时流检测');
        return;
      }
    }
    
    // 增强的播放检查，增加缓冲区检查以预防bufferStalledError
    if (!playbackCheckInterval.value && !reconnectFailCount.value) {
      playbackCheckInterval.value = setInterval(() => {
        // 如果页面在后台，跳过检测
        if (document.hidden) {
          return;
        }
        
        const initialTime = videoElement.currentTime;
        
        // 检查2: 缓冲区状态检查
        try {
          const buffered = videoElement.buffered;
          if (buffered && buffered.length > 0) {
            const currentTime = videoElement.currentTime;
            const bufferedEnd = buffered.end(buffered.length - 1);
            const bufferRemaining = bufferedEnd - currentTime;
            
            console.log(`缓冲区检查: 当前时间=${currentTime.toFixed(2)}, 缓冲结束=${bufferedEnd.toFixed(2)}, 剩余缓冲=${bufferRemaining.toFixed(2)}秒`);
            
            // 如果剩余缓冲区小于2秒，提前预警并尝试恢复
            if (bufferRemaining < 2 && !videoElement.paused) {
              console.warn(`缓冲区不足预警: 剩余缓冲仅${bufferRemaining.toFixed(2)}秒，尝试增加缓冲`);
              
              // 策略1: 对于HLS流，尝试切换到更低的码率
              if (playbackMode.value === 'hlsjs' && hlsPlayer) {
                try {
                  const currentLevel = hlsPlayer.currentLevel;
                  const levels = hlsPlayer.levels || [];
                  
                  if (levels.length > 1 && currentLevel > 0) {
                    console.log(`尝试降低HLS码率级别: 从${currentLevel}降到${currentLevel - 1}`);
                    hlsPlayer.currentLevel = currentLevel - 1;
                  }
                } catch (e) {
                  console.warn('切换HLS码率级别失败:', e);
                }
              }
            }
          }
        } catch (e) {
          console.warn('缓冲区检查失败:', e);
        }
        
        setTimeout(() => {
          // 再次检查页面是否在后台
          if (document.hidden) {
            return;
          }
          
          const newTime = videoElement.currentTime;
          const timeDiff = Math.abs(newTime - initialTime);
          
          // 如果视频在播放但画面静止，说明在播放缓存
          if (timeDiff < 0.1 && !videoElement.paused) {
            console.warn('检测到视频静止，可能正在播放缓存');
            // 检查是否应该进行重连
            if (shouldAttemptReconnect()) {
              forceVideoReconnect(videoElement);
            }
          }
        }, 2000);
      }, 3000); // 更频繁的检查，从10秒改为3秒
    }
  };

// 检查播放状态（带时间戳验证）
const checkPlaybackStatus = (videoElement, reconnectTimestamp) => {
  setTimeout(() => {
    if (reconnectFailCount.value === 0) return;
    
    const currentTime = videoElement.currentTime;
    const initialTimestamp = Date.now();
    
    // 2秒后检查播放进度
    setTimeout(() => {
      const newTime = videoElement.currentTime;
      const timeDiff = Math.abs(newTime - currentTime);
      const timePassed = Date.now() - initialTimestamp;
      
      // 获取缓冲区信息
      const buffered = videoElement.buffered;
      const bufferedEnd = buffered.length > 0 ? buffered.end(buffered.length - 1) : 0;
      
      // 主要故障判断标准：
      // 1. 时间没有进展
      // 2. 当前时间接近缓冲区末尾
      // 3. 等待时间过长（表明卡在加载中）
      const isStalled = timeDiff < 0.1 || 
                        (newTime >= bufferedEnd - 0.5) ||
                        timePassed > 3000;
      
      if (isStalled) {
        console.warn('重连失败：视频流中断');
        updateConnectionStatus('warning', `重连中 (${reconnectFailCount.value}/3)`);
      } 
      // 播放恢复：重置状态
      else {
        console.log('视频重连成功');
        reconnectFailCount.value = 0;
        updateConnectionStatus('success', '已连接');
      }
    }, 2000);
  }, 1000);
};

// 处理播放错误
const handlePlayError = (error) => {
  console.warn('播放失败:', error);
  if (reconnectFailCount.value >= 3) {
    stopKeepAlive();
    emitReconnectFailed();
  } else {
    updateConnectionStatus('warning', `重连中 (${reconnectFailCount.value}/3)`);
  }
};

// 更新连接状态
const updateConnectionStatus = (type, text) => {
  connectionStatus.value = { type, text };
  hasError.value = (type !== "success");
  errorMessage.value = hasError.value ? text : "";
};

// 发送重连失败事件
const emitReconnectFailed = () => {
  emit("reconnectFailed", { 
    url: internalRtspUrl.value,
    attempts: 3,
    error: '视频流已断开连接'
  });
  
  connectionStatus.value = { type: "danger", text: "连接断开" };
  hasError.value = true;
  errorMessage.value = "视频流连接失败，请手动重试";
};

// 停止保活检测
const stopKeepAlive = () => {
  clearInterval(playbackCheckInterval.value);
  playbackCheckInterval.value = null;
  
  if (keepAliveInterval.value) {
    clearInterval(keepAliveInterval.value);
    keepAliveInterval.value = null;
  }
  
  if (backgroundPlaybackInterval.value) {
    clearInterval(backgroundPlaybackInterval.value);
    backgroundPlaybackInterval.value = null;
  }
};

// 监听props变化
watch(() => props.rtspUrl, (newUrl) => {
  if (newUrl && newUrl !== internalRtspUrl.value) {
    internalRtspUrl.value = newUrl;
    if (props.autoplay) {
      startStream();
    }
  }
});

// 监听视频状态变化
watch(() => props.videoStatus, (newStatus) => {
  console.log('视频状态变化:', newStatus);
  
  if (newStatus === 'disabled' || newStatus === 'offline') {
    // 如果状态变为停用，停止播放和检测
    console.log('视频状态变为停用，停止播放和检测');
    stopStream();
    connectionStatus.value = { type: "info", text: "已停用" };
  } else if (newStatus === 'active') {
    // 如果状态变为激活，重新启动播放
    console.log('视频状态变为激活，重新启动播放');
    if (props.autoplay && internalRtspUrl.value) {
      startStream();
    }
  }
});

// 生命周期
onMounted(() => {
  if (props.rtspUrl) {
    internalRtspUrl.value = props.rtspUrl;
    if (props.autoplay) {
      startStream();
    }
  }
  
  // 添加页面可见性变化监听器
  document.addEventListener('visibilitychange', onVisibilityChange);
  
  // 添加全局错误处理器来捕获 SourceBuffer 错误
  const originalErrorHandler = window.onerror;
  window.onerror = function(message, source, lineno, colno, error) {
    // 检查是否是 SourceBuffer 相关错误
    if (message && typeof message === 'string' && 
        (message.includes('SourceBuffer') || message.includes('InvalidStateError'))) {
      console.log('捕获到 SourceBuffer 错误，页面可能在后台:', message);
      // 如果是后台错误，不显示错误信息
      if (document.hidden) {
        return true; // 阻止错误显示
      }
    }
    
    // 调用原始错误处理器
    if (originalErrorHandler) {
      return originalErrorHandler(message, source, lineno, colno, error);
    }
    return false;
  };
  
  // 添加 Promise 错误处理器
  window.addEventListener('unhandledrejection', function(event) {
    // 检查是否是 SourceBuffer 相关错误
    if (event.reason && event.reason.message && 
        (event.reason.message.includes('SourceBuffer') || 
         event.reason.message.includes('InvalidStateError'))) {
      console.log('捕获到未处理的 SourceBuffer Promise 错误:', event.reason.message);
      // 如果是后台错误，阻止默认处理
      if (document.hidden) {
        event.preventDefault();
        return;
      }
    }
  });
});

onUnmounted(() => {
  stopStream();
  
  // 确保退出全屏模式
  if (isFullscreen.value) {
    document.body.style.overflow = '';
  }
  
  // 移除页面可见性变化监听器
  document.removeEventListener('visibilitychange', onVisibilityChange);
});

// 暴露方法
defineExpose({
  startStream,
  stopStream,
  setStream,
  retryConnection,
  toggleFullscreen,
  isFullscreen,
});
</script>

<style scoped>
.rtsp-video-player {
  position: relative;
  width: 100%;
  height: 100%;
  background: #000;
  border-radius: 6px;
  overflow: hidden;
  transition: all 0.2s ease;
}

.rtsp-video-player.fullscreen {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 9999;
  border-radius: 0;
}

.video-container {
  position: relative;
  width: 100%;
  height: 100%;
}

.video-container video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.loading-overlay,
.error-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: white;
  text-align: center;
}

.loading-icon {
  animation: spin 1s linear infinite;
}

.error-icon {
  color: #f56c6c;
}

.loading-text,
.error-text {
  font-size: 14px;
  background: rgba(0, 0, 0, 0.7);
  padding: 8px 12px;
  border-radius: 4px;
}

.status-info {
  position: absolute;
  top: 10px;
  left: 10px;
  display: flex;
  gap: 8px;
  z-index: 5;
}

.format-tag,
.mode-tag {
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 600;
  background: rgba(0, 0, 0, 0.7);
  color: white;
}

.format-tag {
  background: rgba(40, 167, 69, 0.8);
}

.mode-tag {
  background: rgba(0, 123, 255, 0.8);
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.control-panel {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  background: linear-gradient(rgba(0, 0, 0, 0.8), transparent);
  padding: 16px;
  z-index: 10;
}

.stream-input {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

.stream-input .el-input {
  flex: 1;
}

.status-display {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.connection-time {
  color: white;
  font-size: 12px;
  background: rgba(0, 0, 0, 0.5);
  padding: 4px 8px;
  border-radius: 4px;
}

.preset-streams {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.preset-streams .el-button {
  font-size: 12px;
  padding: 4px 8px;
}

.fullscreen-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 10000;
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s ease;
  color: white;
}

.fullscreen-btn:hover {
  background: rgba(0, 0, 0, 0.8);
  transform: scale(1.1);
}

.fullscreen-btn .el-icon {
  font-size: 18px;
  color: white;
}

.fullscreen-exit-btn {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 10000;
  background: rgba(0, 0, 0, 0.7);
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s ease;
  color: white;
}

.fullscreen-exit-btn:hover {
  background: rgba(0, 0, 0, 0.9);
  transform: scale(1.1);
}

.fullscreen-exit-btn .el-icon {
  font-size: 35px !important;
  color: white;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .control-panel {
    padding: 12px;
  }
  
  .stream-input {
    flex-direction: column;
  }
  
  .preset-streams {
    gap: 4px;
  }
  
  .preset-streams .el-button {
    font-size: 11px;
    padding: 2px 6px;
  }
}
</style>